深入理解 iOS 热修复原理 您所在的位置:网站首页 ios aspects 深入理解 iOS 热修复原理

深入理解 iOS 热修复原理

#深入理解 iOS 热修复原理| 来源: 网络整理| 查看: 265

原文链接

背景

顾名思义热修复就是使 App 具备线上修复 bug 的能力,但是遗憾的是苹果出于安全的考虑禁用了热修复。虽然 App 审核加快了,但是依然无法很好的控制线上 bug 的影响范围。由于 JSPatch 存在审核风险,所以我们需要另辟蹊径,自研一套适合自己的热修复框架。

目标

大部分线上 bug 并不需要完全替换原方法实现才能修复问题,我们可以在原来的方法实现前后增加一些自定的方法调用,或者是修改原方法的调用参数,或者是修改其内部的某一个方法调用即可修复问题。

- (void)sayHelloTo:(NSString *)name { // 当 name = nil 会发生 nil 异常。所以我们需要加一个 nil 保护逻辑 // 像这种情况就不需要完全替换原方法实现,只需要在该方法调用前增加一个 if 条件语句即可 //fix code // if (name == nil) { // return; // } [self.nameList addObject:name]; NSLog(@"Hello %@", name); }

综上所述,热修复只需要具备以下几点即可:

方法替换为空实现 方法参数修改 方法返回值修改 方法调用前后插入自定义代码 支持任意 OC 方法调用 支持赋值语句 支持 if 语句:==、!=、>、>=、 Assemble)

解决办法:

使用__bridge_transfer修饰符将返回对象的内存管理权移交出来,让外部对象管理其内存 // 方法1 id resultObj = nil; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; invocation.target = [NSObject class]; invocation.selector = @selector(new); [invocation invoke]; void *result; [invocation getReturnValue:&result]; if ([selName isEqualToString:@"alloc"] || [selName isEqualToString:@"new"] || [selName isEqualToString:@"copy"] || [selName isEqualToString:@"mutableCopy"]) { resultObj = (__bridge_transfer id)result; } else { resultObj = (__bridge id)result; } 采用常规方法调用代替 NSInvocation // 方法2 id resultObj = nil; if ([selName isEqualToString:@"alloc"]) { resultObj = [[target class] alloc]; } else if ([selName isEqualToString:@"new"]) { resultObj = [[target class] new]; } else if ([selName isEqualToString:@"copy"]) { resultObj = [target copy]; } else if ([selName isEqualToString:@"mutableCopy"]) { resultObj = [target mutableCopy]; } else { NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; invocation.target = [NSObject class]; invocation.selector = @selector(new); [invocation invoke]; void *result; [invocation getReturnValue:&result]; resultObj = (__bridge id)result; } 审核分析

其实能不能成功上线是热修复的首要前提,我们辛辛苦苦开的框架如果上不了线,那一切都是徒劳无功。下面就来分析下其审核风险。

首先这个是我们自研的,所以苹果审核无法通过静态代码扫描识别。 其次系统库内部也大量使用了消息转发机制。可以通过符号断点验证_objc_msgForward和forwardInvocation:。所以不存在风险。 苹果无法采用动态检验消息转发,非系统调用都不能使用,这个成本太大了,几乎不可能。 Aspects 库目前线上有大量使用,为此不用担心。就算 Aspects 被禁用,参考 Aspects 自己实现也不难。

综上所述:无审核风险。

当然热修复框架只是为了更好的控制线上 bug 影响范围和给用户更好的体验。不建议基于其它目的使用🤔

后记

随着项目的业务复杂度增加,线上问题可能存在一些 C 函数的动态调用和 block 参数的修改,这边介绍一个强大的库,外部函数接口:libffi,它也可以拦截函数和获取函数调用参数。相比 Aspects,其功能更加强大,不但可以动态调用 C 函数,而且还可以用 libffi 实现一套基于 IMP 替换(拥有更好的性能)的热修复框架。有兴趣的童鞋请参考:libffi doc 和 如何动态调用 C 函数

取名深入只是为了引人注目,实则只是个人的一点心得。由于水平有限,如有不对之处,欢迎大家批评指正。

如果觉得文章不错的话,欢迎🌟以资鼓励😄

温馨提示:

阅读文章的时候建议搭配示例 HotFixDemo,这样理解会更加深刻。

参考文献 Objective-C Runtime Programming Guide NSInvocation returns value but makes app crash with EXC_BAD_ACCESS JSPatch 实现原理详解 objc_msgSend_stret objc_msgSend() Tour Part 1: The Road Map -rac_signalForSelector: may fail for struct returns Objective-C Automatic Reference Counting (ARC) Aspects


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有